﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using System.Web.Hosting;

namespace SelfManagement.Utility.Extensions
{
    public static class StringExtensions
    {

        #region Null extension

        public static bool IsNullOrEmpty(this string source)
        {
            return string.IsNullOrEmpty(source);
        }

        public static bool IsNullOrWhiteSpace(this string source)
        {
            return string.IsNullOrWhiteSpace(source);
        }

        public static bool IsNotNullAndNotEmpty(this string source)
        {
            return !string.IsNullOrEmpty(source);
        }

        public static bool IsNotNullAndNotWhiteSpace(this string source)
        {
            return !string.IsNullOrWhiteSpace(source);
        }

        public static string TrimEvenNull(this string source)
        {
            return source == null ? null : source.Trim();
        }

        #endregion

        #region Hash

        public static string GetMD5Hash(this string stringToHash)
        {
            return GetMD5Hash(stringToHash, Encoding.UTF8);
        }

        public static string GetMD5Hash(this string stringToHash, Encoding encoding)
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] encryptedBytes = md5.ComputeHash(encoding.GetBytes(stringToHash));
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < encryptedBytes.Length; i++)
            {
                stringBuilder.AppendFormat("{0:x2}", encryptedBytes[i]);
            }

            return stringBuilder.ToString();
        }

        #endregion

        #region 按命名规则转换

        /// <summary>
        /// 将字符串转换成Camel命名法字符串
        /// </summary>
        /// <param name="value">字符串</param>
        /// <returns>Camel命名法字符串</returns>
        public static string ToCamelCase(this string source)
        {
            return source.Substring(0, 1).ToLower() + source.Substring(1).Replace(" ", "");
        }

        /// <summary>
        /// 将字符串转换成Pascal命名法字符串
        /// </summary>
        /// <param name="value">字符串</param>
        /// <returns>Pascal命名法字符串</returns>
        public static string ToPascalCase(this string source)
        {
            return source.Substring(0, 1).ToUpper() + source.Substring(1).Replace(" ", "");
        }

        #endregion

        #region 编码转换

        public static byte[] ToBase64Bytes(this string source)
        {
            return Convert.FromBase64String(source);
        }

        public static string ToBase64String(this byte[] source)
        {
            return Convert.ToBase64String(source);
        }

        public static byte[] ToUTF8Bytes(this string source)
        {
            return Encoding.UTF8.GetBytes(source);
        }

        public static string ToUTF8String(this byte[] source)
        {
            return Encoding.UTF8.GetString(source);
        }

        #endregion

        #region GZIP压缩解压

        /// <summary>
        /// 压缩字符串
        /// </summary>
        /// <param name="str">原字符串</param>
        /// <returns>压缩后的字符串</returns>
        public static string Compress(this string source)
        {
            byte[] buffer = UTF8Encoding.Unicode.GetBytes(source);
            MemoryStream ms = new MemoryStream();
            using (GZipStream gzip = new GZipStream(ms, CompressionMode.Compress))
            {
                gzip.Write(buffer, 0, buffer.Length);
            }
            return Convert.ToBase64String(ms.GetBuffer()).TrimEnd('\0');
        }

        /// <summary>
        /// 解压缩字符串
        /// </summary>
        /// <param name="str">压缩后的字符串</param>
        /// <returns>原字符串</returns>
        public static string Decompress(this string source)
        {
            byte[] buffer = Convert.FromBase64String(source);
            MemoryStream ms = new MemoryStream();
            MemoryStream msOut = new MemoryStream();
            ms.Write(buffer, 0, buffer.Length);
            ms.Position = 0;
            byte[] writeData = new byte[4096];
            using (GZipStream gzip = new GZipStream(ms, CompressionMode.Decompress))
            {
                int n;
                while ((n = gzip.Read(writeData, 0, writeData.Length)) != 0)
                {
                    msOut.Write(writeData, 0, n);
                }
            }
            return UTF8Encoding.Unicode.GetString(msOut.GetBuffer()).TrimEnd('\0');
        }

        #endregion

        #region 将字符串转换成字符串集合

        /// <summary>
        /// 将字符串转换成字符串集合
        /// </summary>
        /// <param name="formatValue">原字符串</param>
        /// <param name="comma">分隔符</param>
        /// <returns>字符串集合</returns>
        public static List<string> ToList(this string formatValue, char comma)
        {
            List<string> list = new List<string>();
            if (formatValue.IsNotNullAndNotEmpty())
            {
                list.AddRange(formatValue.Split(comma));
            }
            return list;
        }

        public static List<string> ToList(this string formatValue)
        {
            return ToList(formatValue, ',');
        }

        #endregion

        #region 比较

        public static bool EqualsNoCase(this string source, string compare)
        {
            if (string.IsNullOrWhiteSpace(source) || string.IsNullOrWhiteSpace(compare))
            {
                return false;
            }
            return source.Equals(compare, StringComparison.OrdinalIgnoreCase);
        }

        public static bool ContainsNoCase(this string source, string compare)
        {
            source = source ?? "";
            compare = compare ?? "";
            return source.ToLower().Contains(compare.ToLower());
        }

        #endregion

        #region Web扩展

        /// <summary>
        /// 获取html中所有的图片路径
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        public static List<string> GetImageUrl(this string html)
        {
            Regex RegImgSrc = new Regex(@"<img\b[^<>]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""']?[\s\t\r\n]*(?<imgUrl>[^\s\t\r\n""'<>]*)[^<>]*?/?[\s\t\r\n]*>", RegexOptions.IgnoreCase);
            List<string> urls = new List<string>();
            MatchCollection mc = RegImgSrc.Matches(html);
            // 取得匹配项列表
            if (mc.IsNull() && mc.Count > 0)
            {
                foreach (Match match in mc)
                {
                    if (match.Groups["imgUrl"] != null && match.Groups["imgUrl"].Value.IsNotNullAndNotWhiteSpace())
                    {
                        urls.Add(match.Groups["imgUrl"].Value.Trim());
                    }
                }
            }
            return urls;
        }


        /// <summary>
        /// 获取html中所有的第一张图片的路径
        /// </summary>
        public static string GetFirstImageUrl(this string html)
        {
            Regex RegImgSrc = new Regex(@"<img\b[^<>]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""']?[\s\t\r\n]*(?<imgUrl>[^\s\t\r\n""'<>]*)[^<>]*?/?[\s\t\r\n]*>", RegexOptions.IgnoreCase);

            MatchCollection mc = RegImgSrc.Matches(html);
            // 取得匹配项列表
            if (mc.IsNotNull() && mc.Count > 0)
            {
                foreach (Match match in mc)
                {
                    if (match.Groups["imgUrl"] != null && match.Groups["imgUrl"].Value.IsNotNullAndNotWhiteSpace())
                    {
                        return match.Groups["imgUrl"].Value.Trim();
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 除掉字符串中的web标签
        /// </summary>
        public static string RemoveTags(this string html)
        {
            string result = String.IsNullOrEmpty(html)
                        ? ""
                        : Regex.Replace(html, "<[^<>]*>", "", RegexOptions.Singleline);

            result = String.IsNullOrEmpty(result)
                        ? ""
                        : Regex.Replace(result, "&nbsp;", "", RegexOptions.Singleline);

            return result;
        }


        /// <summary>
        /// 连接查询字符串和url
        /// </summary>
        public static string AppendQueryString(this string url, string qs)
        {
            string split = url.IndexOf('?') > 0 ? "&" : "?";
            return string.Concat(url, split, qs);
        }

        /// <summary>
        /// 为url添加一个查询字符串
        /// </summary>
        public static string AppendQueryString(this string url, string name, string val)
        {
            string split = url.IndexOf('?') > 0 ? "&" : "?";
            return string.Format("{0}{1}{2}={3}", url, split, name, val);
        }

        /// <summary>
        /// 将换行符号转化为web的换行
        /// </summary>
        public static string WrapLine(this string source)
        {
            return new StringBuilder(source).Replace("\r\n", "<br/>")
                .Replace("\n", "<br/>")
                .ToString();
        }

        /// <summary>
        /// 将换行符号转化为web的换行，空格转化为web的空格
        /// </summary>
        public static string WrapLineAndSpace(this string source)
        {
            return new StringBuilder(source).Replace("\r\n", "<br/>")
                    .Replace("\n", "<br/>").Replace(" ", "&nbsp;")
                    .ToString();
        }

        /// <summary>
        /// 截取字符串，并补充省略号
        /// </summary>
        public static string SubstringWithDots(this string source, int length = 20)
        {
            if (source.IsNotNullAndNotWhiteSpace() && source.Length > length)
            {
                return source.Substring(0, length) + "...";
            }
            return source ?? string.Empty;
        }

        #endregion

        public static string HidePhone(this string phone)
        {
            if (phone.IsNotNullAndNotEmpty() && phone.Length >= 11)
            {
                return $"{phone.Substring(0, 3)}****{phone.Substring(7, 4)}";
            }
            return "***********";
        }

        public static string GetPhysicalPath(this string path)
        {
            if (path.IndexOf(":\\") > 0)
                return path;
            if (!path.StartsWith("~"))
            {
                if (!path.StartsWith("/"))
                    path = "~/" + path;
                else
                    path = "~" + path;
            }
            if (HttpContext.Current != null)
                return HttpContext.Current.Server.MapPath(path);
            else
            {
                var tpath = path.Replace("~/", "").Replace("/", "\\");
                string fp = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, tpath);
                if (Directory.Exists(fp) || File.Exists(fp))
                    return fp;

                fp = string.Format("{0}{1}", HttpRuntime.AppDomainAppPath, tpath);
                if (Directory.Exists(fp) || File.Exists(fp))
                    return fp;

                fp = string.Format("{0}{1}", HttpRuntime.BinDirectory, tpath);
                if (Directory.Exists(fp) || File.Exists(fp))
                    return fp;
            }
            if (!string.IsNullOrEmpty(path))
                return HostingEnvironment.MapPath(path);

            return path;
        }
    }
}
